package com.chatplus.application.aiprocessor.platform.chat;

import cn.bugstack.openai.executor.parameter.CompletionRequest;
import cn.bugstack.openai.executor.parameter.Functions;
import cn.bugstack.openai.executor.parameter.Message;
import cn.bugstack.openai.session.OpenAiSession;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chatplus.application.aiprocessor.constant.AIConstants;
import com.chatplus.application.aiprocessor.util.ChatWebSocketUtil;
import com.chatplus.application.common.constant.GroupCacheNames;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.common.util.CacheGroupUtils;
import com.chatplus.application.common.util.PlusJsonUtils;
import com.chatplus.application.domain.dto.AdminConfigDto;
import com.chatplus.application.domain.dto.ApiKeyDto;
import com.chatplus.application.domain.dto.FunctionParametersDto;
import com.chatplus.application.domain.entity.basedata.ApiKeyEntity;
import com.chatplus.application.domain.entity.functions.FunctionEntity;
import com.chatplus.application.domain.request.ws.ChatWebSocketRequest;
import com.chatplus.application.enumeration.AiPlatformEnum;
import com.chatplus.application.service.functions.FunctionService;
import com.google.common.collect.Lists;
import lombok.Setter;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * Chat 类型 AI 处理器服务接口
 */
public abstract class ChatProcessorService {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(ChatProcessorService.class);
    private FunctionService functionService;

    private boolean enableProxy = false;
    @Setter
    protected ChatWebSocketRequest chatRequest;
    protected static final List<ApiKeyDto> OPEN_API_KEY_CACHE = new ArrayList<>();
    protected static final Map<AiPlatformEnum, OpenAiSession> OPEN_AI_SESSION_CACHE = new ConcurrentHashMap<>();

    @Autowired
    public void setFunctionService(FunctionService functionService) {
        this.functionService = functionService;
    }

    /**
     * 流式输出
     */
    public abstract void processStream() throws Exception;

    /**
     * 处理器,阻塞式输出，直接返回
     */
    public abstract String processSync();

    /**
     * AI 渠道处理器
     */
    public abstract AiPlatformEnum getChannel();

    /**
     * 函数设置
     *
     * @return 返回函数列表
     */
    public List<Functions> getFunctionList() {
        AdminConfigDto adminConfigDto = CacheGroupUtils.get(GroupCacheNames.SYS_AI_SETTING, AIConstants.SYSTEM_CONFIG_REDIS_KEY);
        if (adminConfigDto == null || adminConfigDto.isEnabledFunction() == Boolean.FALSE) {
            return Lists.newArrayList();
        }
        List<FunctionEntity> functionList = functionService.list(Wrappers.<FunctionEntity>lambdaQuery().eq(FunctionEntity::getEnabled, Boolean.TRUE));
        if (CollectionUtils.isEmpty(functionList)) {
            return Lists.newArrayList();
        }
        return functionList.stream().map(functionEntity -> {
            FunctionParametersDto functionParametersDto = functionEntity.getParameters();
            Map<String, FunctionParametersDto.FunctionFieldDetailBean> propertiesMap
                    = functionParametersDto.getProperties();
            JSONObject properties = new JSONObject();
            if (propertiesMap != null && !propertiesMap.isEmpty()) {
                propertiesMap.forEach((k, v) -> {
                    JSONObject propertiesField = new JSONObject();
                    propertiesField.putOpt("type", v.getType());
                    propertiesField.putOpt("description", v.getDescription());
                    properties.putOpt(k, propertiesField);
                });
            }
            Functions.Parameters parameters = Functions.Parameters.builder()
                    .type("object")
                    .properties(properties)
                    .required(functionParametersDto.getRequired()).build();
            return Functions.builder()
                    .name(functionEntity.getName())
                    .description(functionEntity.getDescription())
                    .parameters(parameters)
                    .build();
        }).toList();
    }

    public CompletionRequest getCompletionRequest() {
        // 组装请求参数
        List<Message> messages = new ArrayList<>();
        chatRequest.getChatContextList().forEach(msg -> {
            if (StringUtils.isNotEmpty(msg.getSystem())) {
                Message promptMessage = Message.builder().role(CompletionRequest.Role.SYSTEM).content(msg.getSystem()).build();
                messages.add(promptMessage);
            }
            if (StringUtils.isNotEmpty(msg.getPrompt())) {
                Message promptMessage = Message.builder().role(CompletionRequest.Role.USER).content(msg.getPrompt()).build();
                messages.add(promptMessage);
            }
            if (StringUtils.isNotEmpty(msg.getReply())) {
                Message replyMessage = Message.builder().role(CompletionRequest.Role.ASSISTANT).content(msg.getReply()).build();
                messages.add(replyMessage);
            }
        });
        // 1. 创建参数
        return CompletionRequest.builder()
                .stream(true)
                .messages(messages)
                .functions(getFunctionList())
                .user(chatRequest.getUserId().toString())
                .tag(chatRequest.getSessionId())
                .model(chatRequest.getModelName())
                .build();
    }

    /**
     * 停止输出会话
     *
     * @param sessionId 会话ID
     */
    public void stopChat(String sessionId) {
        getSessionFactory().cancelRequest(sessionId);
    }

    /**
     * 初始化会话工厂
     */
    public abstract void initSessionFactory();

    /**
     * 获取会话工厂,没有就初始化，有就从缓存中获取
     *
     * @return 会话工厂
     */
    public synchronized OpenAiSession getSessionFactory() {
        initSessionFactory();
        OpenAiSession openAiSession = OPEN_AI_SESSION_CACHE.get(getChannel());
        if (enableProxy) {
            OkHttpClient client = openAiSession.getClient();
            if (!isProxyAvailable(client)) {
                ChatWebSocketUtil.replyErrorMessage(chatRequest.getSessionId(), "抱歉，代理出问题了，请联系管理员！");
                return null;
            }
        }
        return openAiSession;
    }

    /**
     * 初始化每个平台的 API KEY
     */
    public synchronized void instance() {
        enableProxy = false;
        String json = CacheGroupUtils.get(GroupCacheNames.SYS_AI_CHAT_API_KEY, getChannel());
        List<ApiKeyEntity> apiKeys = PlusJsonUtils.parseArray(json, ApiKeyEntity.class);
        // // 更新 API KEY 的最后使用时间
        if (CollectionUtils.isEmpty(apiKeys)) {
            ChatWebSocketUtil.replyErrorMessage(chatRequest.getSessionId(), "抱歉😔😔😔，系统已经没有可用的 API KEY，请联系管理员！");
            return;
        }
        // 做清空操作
        OPEN_API_KEY_CACHE.clear();
        Map<AiPlatformEnum, List<ApiKeyEntity>> apiKeyMap = apiKeys.stream()
                .collect(Collectors.groupingBy(ApiKeyEntity::getPlatform));
        apiKeyMap.get(getChannel()).forEach(apiKeyEntity -> {
            String value = apiKeyEntity.getValue();
            String apiUrl = apiKeyEntity.getApiUrl();
            if (StringUtils.isEmpty(apiUrl)) {
                apiUrl = AIConstants.DefaultBaseUrl.getDefaultBaseUrlByChannel(getChannel());
            }
            if (StringUtils.isNotEmpty(value) && StringUtils.isNotEmpty(apiUrl)) {
                ApiKeyDto apiKeyDto = new ApiKeyDto();
                apiKeyDto.setUrl(apiUrl);
                apiKeyDto.setUrl(apiUrl);
                apiKeyDto.setApiKey(apiKeyEntity.getValue());
                apiKeyDto.setNotifyUrl(apiKeyEntity.getNotifyUrl());
                // 是否使用代理
                if (Boolean.TRUE.equals(apiKeyEntity.getUseProxy())
                        && StringUtils.isNotEmpty(apiKeyEntity.getProxyUrl())) {
                    apiKeyDto.setProxyUrl(apiKeyEntity.getProxyUrl());
                    enableProxy = true;
                }
                OPEN_API_KEY_CACHE.add(apiKeyDto);
            }
        });
        if (OPEN_API_KEY_CACHE.isEmpty()) {
            ChatWebSocketUtil.replyErrorMessage(chatRequest.getSessionId(), "抱歉😔😔😔，系统已经没有可用的 API KEY，请联系管理员！");
        }
    }
    /**
     * 检查代理是否可用
     * @return 是否可用
     */
    public boolean isProxyAvailable(OkHttpClient client) {
        boolean isProxyAvailable = true;
        // 目前是检查所有的url是否可用，如果某一个url不可用就会返回false，后续做多key轮询的时候要改这个地方
        for (ApiKeyDto item : OPEN_API_KEY_CACHE) {
            Request request = new Request.Builder()
                    .url(item.getUrl())
                    .build();
            try (Response response = client.newCall(request).execute()) {
                isProxyAvailable = response.isSuccessful();
            } catch (IOException e) {
                LOGGER.message("代理失效").exception(e).error();
                isProxyAvailable = false;
                break;
            }
        }
        return isProxyAvailable;
    }
}
